package com.vlyman.aop;

import com.vlyman.annotation.ValidateField;
import com.vlyman.annotation.ValidateGroup;
import com.vlyman.exception.ValidateException;
import com.vlyman.rtn.RtnResult;
import com.vlyman.utils.AspectUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * 类描述：
 *  接口参数校验切面
 * @author chenjs
 * @date 2018/10/11 10:54
 **/
@Aspect
@Slf4j
@Component
@Order(2)
public class ValidateAspect {

    @Pointcut("@annotation(com.vlyman.annotation.ValidateGroup)")
    public void validatePointCut(){}

    /**
     * 方法描述：
     *   aop方式校验接口参数
     *  @author chenjs
     *  @param proceedingJoinPoint
     *  @return Object
     *  @date 2018/10/11 11:45
     */
    @Around("validatePointCut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        ValidateGroup validateGroup = AspectUtil.getAnnotation(proceedingJoinPoint, ValidateGroup.class);
        ValidateField[] fields = validateGroup.fileds();
        //获取传入参数
        Object[] args = proceedingJoinPoint.getArgs();
        try {
            validate(fields, args);
            return proceedingJoinPoint.proceed();
        } catch (ValidateException e) {
            //仅catch校验失败错误，其他错误继续向上层抛出
            log.error("接口参数校验失败！", e);
            return RtnResult.paramValidationError();
        }
    }

    /**
     * 方法描述：
     *   利用java反射机制，获取、分割需校验的参数
     *  @author chenjs
     *  @param fields
     *  @param args
     *  @return
     *  @date 2018/10/12 09:53
     */
    private void validate(ValidateField[] fields, Object[] args) throws Exception {
        for (ValidateField field : fields) {
            int index = field.index();
            //参数可以是一个对象，也可以是其他String等基础数据类型，存在多个参数情况
            Object[] attributes;
            if (StringUtils.isEmpty(field.fieldName().trim())) {
                attributes = new Object[]{args[index]};
            } else {
                attributes = AspectUtil.getAttributeFromArgByFieldName(field.fieldName(), args[index]);
            }
            validateAttributes(field, attributes);
        }
    }

    /**
     * 方法描述：
     *   校验参数
     *  @author chenjs
     *  @param field
     *  @param attributes
     *  @return
     *  @date 2018/10/12 09:54
     */
    private void validateAttributes(ValidateField field, Object[] attributes) throws Exception {
        for (int i = 0; i < attributes.length; i++) {
            //判断参数是否为null
            if (field.notNull() && attributes[i] == null) {
                throw new ValidateException("参数"
                        + AspectUtil.findAttributeNameByIndex(field.fieldName(), i)
                        + "不能为null");
            }
            //判断参数是否为空，针对String类型参数
            if (field.notBlank() && !StringUtils.hasText((String) attributes[i])) {
                throw new ValidateException("参数"
                        + AspectUtil.findAttributeNameByIndex(field.fieldName(), i)
                        + "不能为空");
            }
            //判断参数长度最小值，针对String类型参数
            if (field.isRequire() && field.minLen() > 0 && ((String) attributes[i]).length() < field.minLen()) {
                throw new ValidateException("参数"
                        + AspectUtil.findAttributeNameByIndex(field.fieldName(), i)
                        + "长度不能少于" + field.minLen());
            }
            //判断参数长度最大值，针对String类型参数
            if (field.isRequire() && field.maxLen() > 0 && ((String) attributes[i]).length() > field.maxLen()) {
                throw new ValidateException("参数"
                        + AspectUtil.findAttributeNameByIndex(field.fieldName(), i)
                        + "长度不能大于" + field.minLen());
            }
            //判断参数最小值，针对Integer类型参数
            if (field.isRequire() && field.minVal() != -9999999 && (Integer) attributes[i] < field.minVal()) {
                throw new ValidateException("参数"
                        + AspectUtil.findAttributeNameByIndex(field.fieldName(), i)
                        + "的值不能少于" + field.minLen());
            }
            //判断参数最大值，针对Integer类型参数
            if (field.isRequire() && field.maxVal() != 9999999 && (Integer) attributes[i] > field.maxVal()) {
                throw new ValidateException("参数"
                        + AspectUtil.findAttributeNameByIndex(field.fieldName(), i)
                        + "的值不能大于" + field.minLen());
            }
            //正则表达式校验，针对String类型
            if (field.isRequire() && !"".equals(field.regStr()) && !((String) attributes[i]).matches(field.regStr())) {
                throw new ValidateException("参数"
                        + AspectUtil.findAttributeNameByIndex(field.fieldName(), i)
                        + "正则表达式校验失败");
            }
        }
    }
}
